package com.zmn.plat.business.impl.push;

import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.plat.business.interfaces.push.ZmnSmsBService;
import com.zmn.plat.common.dictionary.PlatErrorCodeDict;
import com.zmn.plat.common.exception.PlatException;
import com.zmn.plat.constant.sendtemplate.SendSmsStrategyEnum;
import com.zmn.plat.dubbo.dto.push.WeChatSmsDIO;
import com.zmn.plat.dubbo.dto.push.WeChatSmsValueDIO;
import com.zmn.plat.dubbo.dto.sendtemplate.SendSmsDIO;
import com.zmn.plat.manager.constant.MsgTemplateConsts;
import com.zmn.plat.manager.constant.ZmnSmsConsts;
import com.zmn.plat.model.entity.message.*;
import com.zmn.plat.model.entity.push.ZmnSms;
import com.zmn.plat.services.interfaces.message.*;

import lombok.extern.slf4j.Slf4j;

/**
 * @author tanbiao
 * @description
 * @modifier
 * @since 2020/9/26 14:36
 **/
@Service
@Slf4j
public class ZmnSmsBServiceImpl implements ZmnSmsBService {
    @Resource
    MsgTemplateGroupService msgTemplateGroupService;

    @Resource
    MsgTemplateService msgTemplateService;

    @Resource
    MsgWechatTemplateService msgWechatTemplateService;

    @Resource
    MsgSmsTemplateService msgSmsTemplateService;

    @Resource
    MsgBaiduTemplateService msgBaiduTemplateService;

    @Resource
    RedisTemplate<String, String> redisTemplate;

    private static String REDIS_KEY = "plat:pushMsg:baiduApp:formId:";

    private static final int REDIS_OUT_TIME = 7;

    @Override
    public Boolean sendSmsInfo(SendSmsDIO sendSmsDio) {
        if (Objects.isNull(sendSmsDio)) {
            log.error("发送参数为null，不能发送消息");
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        LinkedList<String> baiduMsgPram = null;
        if (CollectionUtil.isNotNullOrEmpty(sendSmsDio.getBaiduAppPrams())) {
            baiduMsgPram = sendSmsDio.getBaiduAppPrams();
            sendSmsDio.setBaiduAppPrams(null);
        }
        ZmnSms sms = BeanMapper.map(sendSmsDio, ZmnSms.class);
        sms.setBaiduAppPrams(baiduMsgPram);

        log.info("[{},发送模板消息转化后入参，msg:{}", "发送模板消息", JSONObject.toJSONString(sms));

        String weChatPram = this.buildWeChatPram(sendSmsDio);
        if (StringUtil.isNotBlank(weChatPram)) {
            sms.setWeChartParams(weChatPram);
        }

        MsgTemplateGroup msgTemplateGroup = msgTemplateGroupService.findByKey(sms.getGroupId());
        if (Objects.isNull(msgTemplateGroup) || NumberUtil.isNullOrZero(msgTemplateGroup.getGroupId())) {
            log.error("发送消息失败，模板组不存在.msgTemplateGroup={},errorcode:{}", msgTemplateGroup, PlatErrorCodeDict.ERROR_CODE_PUSH_CATEGORY_NULL);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PUSH_CATEGORY_NULL);
        }
        // 发送消息
        Integer resultCode;
        if (NumberUtil.isPositiveInteger(sms.getChannelId()) && NumberUtil.isPositiveInteger(sms.getCityId())) {
            // 如果渠道城市ID都有，发送渠道城市模板
            resultCode = this.sendCityAndChannelTemplate(sms);
        } else if (NumberUtil.isPositiveInteger(sms.getChannelId())) {
            // 只有渠道发送渠道模板
            resultCode = this.sendChannelTemplate(sms);
        } else if (NumberUtil.isPositiveInteger(sms.getCityId())) {
            // 只有城市发送城市模板
            resultCode = this.sendCityTemplate(sms);
        } else {
            // 通用模板
            resultCode = this.sendCommonTemplate(sms);
        }
        return Objects.equals(resultCode, ZmnSmsConsts.MSG_SEND_SUCCESS);
    }

    /**
     * 描述：通过通用模板发送
     *
     * @param sms
     *            消息内容
     * @return java.lang.Integer
     * @author wangjie
     * @since 2020/6/19 13:48
     **/
    private Integer sendCommonTemplate(ZmnSms sms) {

        MsgTemplateQuery query = new MsgTemplateQuery();
        query.setGroupId(sms.getGroupId());
        query.setTemplateType(MsgTemplateConsts.MSG_TEMP_TYPE_CURRENCY);
        query.setStatus(GlobalConsts.YES);
        log.info("通过通用模板发送,query:{}", query);
        List<MsgTemplate> msgTemplateList = msgTemplateService.listByQuery(query);
        log.info("通过通用模板发送,msgTemplateList:{}", msgTemplateList);
        // 通用模板只能有一个
        if (msgTemplateList.size() != 1) {
            log.error("[{}],发送异常，msg:{},errorCode:{}", "发送消息模板", "配置数据异常，通用模板只能有一个", PlatErrorCodeDict.ERROR_CODE_PUSH_MSG_SEND_ERROR_GROUP_HIDDEN);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PUSH_MSG_SEND_ERROR_GROUP_HIDDEN);
        }
        MsgTemplate template = msgTemplateList.stream().findFirst().get();
        return this.sendTemplateSmsInfo(template, sms);
    }

    /**
     * 描述：通过城市模板发送
     *
     * @param sms
     *            消息内容
     * @return java.lang.Integer
     * @author wangjie
     * @since 2020/6/19 13:48
     **/
    private Integer sendCityTemplate(ZmnSms sms) {

        MsgTemplate template = msgTemplateService.findByGroupIdAndTypeAndChannelIdAndCityId(sms.getGroupId(), MsgTemplateConsts.MSG_TEMP_TYPE_CITY, null, sms.getCityId());

        if (Objects.isNull(template) || NumberUtil.isNullOrZero(template.getTemplateId())) {
            return this.sendCommonTemplate(sms);
        } else {
            return this.sendTemplateSmsInfo(template, sms);
        }
    }

    /**
     * 描述：通过渠道模板发送
     *
     * @param sms
     *            消息内容
     * @return java.lang.Integer
     * @author wangjie
     * @since 2020/6/19 13:42
     **/
    private Integer sendChannelTemplate(ZmnSms sms) {
        MsgTemplate template = msgTemplateService.findByGroupIdAndTypeAndChannelIdAndCityId(sms.getGroupId(), MsgTemplateConsts.MSG_TEMP_TYPE_CHANNEL, sms.getChannelId(), null);
        if (Objects.isNull(template) || NumberUtil.isNullOrZero(template.getTemplateId())) {
            return this.sendCommonTemplate(sms);
        } else {
            return this.sendTemplateSmsInfo(template, sms);
        }
    }

    /**
     * 描述：通过渠道城市模板发送
     *
     * @param sms
     *            消息内容
     * @return java.lang.Integer
     * @author wangjie
     * @since 2020/6/19 13:39
     **/
    private Integer sendCityAndChannelTemplate(ZmnSms sms) {
        MsgTemplate template = msgTemplateService.findByGroupIdAndTypeAndChannelIdAndCityId(sms.getGroupId(), MsgTemplateConsts.MSG_TEMP_TYPE_CHANNEL_CITY, sms.getChannelId(), sms.getCityId());

        if (Objects.isNull(template) || NumberUtil.isNullOrZero(template.getTemplateId())) {
            return this.sendCommonTemplate(sms);
        } else {
            return this.sendTemplateSmsInfo(template, sms);
        }
    }

    /**
     * 描述：判断使用哪个消息发送
     *
     * @param msgTemplate
     *            消息模板
     * @param sms
     *            消息内容
     * @return java.lang.Integer
     * @author wangjie
     * @since 2020/6/19 13:39
     **/
    private Integer sendTemplateSmsInfo(MsgTemplate msgTemplate, ZmnSms sms) {

        try {
            if (Objects.isNull(msgTemplate)) {
                log.error("[{}],发送异常，msg:{},sms:{},errorCode:{}", "发送消息模板", "无配置数据", JSONObject.toJSONString(msgTemplate),
                    PlatErrorCodeDict.ERROR_CODE_PUSH_MSG_SEND_ERROR_TEMPLATE_NOT_EXIST);
                throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PUSH_MSG_SEND_ERROR_TEMPLATE_NOT_EXIST);
            }
            if (Objects.isNull(sms)) {
                log.error("[{}],发送异常，msg:{},msgTemplate:{}，errorCode:{}", "发送消息模板", "无配置数据", JSONObject.toJSONString(sms), PlatErrorCodeDict.ERROR_CODE_PUSH_MSG_SEND_ERROR_CONTENT_NOT_EXIST);
                throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PUSH_MSG_SEND_ERROR_CONTENT_NOT_EXIST);
            }
            // 发送百度消息
            boolean isSendBaiduMsg = StringUtil.isNotBlank(sms.getSceneId()) && (StringUtil.isNotBlank(sms.getToUserOpenId()) || StringUtil.isNotBlank(sms.getToUserId()));
            if (isSendBaiduMsg && CollectionUtil.isNotNullOrEmpty(sms.getBaiduAppPrams())) {

                // 检查是否可以发送
                if (!checkBaiduFormIdNum(sms.getSceneId())) {
                    log.error("百度消息发送失败，formId 7天内已被使用,errorCode:{}", PlatErrorCodeDict.ERROR_CODE_PUSH_MSG_SEND_BAIDU_FORM_ID_REPEAT_STR);
                    throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PUSH_MSG_SEND_BAIDU_FORM_ID_REPEAT_STR);
                }

                String dataPram = baiduSmsDIOToJson(sms.getBaiduAppPrams());

                MsgBaiduTemplate baiduTemplate = msgBaiduTemplateService.findByTemplateId(msgTemplate.getTemplateId());
                if (Objects.isNull(baiduTemplate) || NumberUtil.isNullOrZero(baiduTemplate.getMsgBaiduTemplateId())) {
                    log.error("[{}],发送异常，msg:{},data:{}", "发送百度模板消息", "无配置数据", baiduTemplate);
                    log.error("[{}],发送异常，msg:{}", "发送百度模板消息", "尝试发送微信消息");
                    return this.sendWechatMsg(msgTemplate, sms);
                }
                msgTemplate.setBaiduMessage(dataPram);
                msgTemplate.setBaiduTempId(baiduTemplate.getBaiduTempId());
                msgTemplate.setSceneType(baiduTemplate.getSceneType());
                Integer code = SendSmsStrategyEnum.valueOf(SendSmsStrategyEnum.BAIDU.desc).notifyMechanism.doSend(msgTemplate, sms);
                // 发送微信消息
                if (Objects.nonNull(sms.getWeChartParams()) && Objects.nonNull(sms.getOpenId())) {
                    return this.sendWechatMsg(msgTemplate, sms);
                } else {
                    log.info("[{}],微信模板消息推送失败，只推送了百度模板消息", "发送百度模板消息");
                    return code;
                }
            }
            // 发送微信消息
            if (Objects.nonNull(sms.getWeChartParams()) && Objects.nonNull(sms.getOpenId())) {
                return this.sendWechatMsg(msgTemplate, sms);
            }
            // 发送短信
            MsgSmsTemplate smsTemplate = msgSmsTemplateService.findByTemplateId(msgTemplate.getTemplateId());
            if (Objects.isNull(smsTemplate)) {
                log.error("[{}],发送异常，msg:{},errorCode:{}", "发送短信", "无配置数据", PlatErrorCodeDict.ERROR_CODE_PUSH_MSG_SEND_SMS_NO_TEMPLATE);
                throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PUSH_MSG_SEND_SMS_NO_TEMPLATE);
            }
            msgTemplate.setMessage(smsTemplate.getMessage());
            msgTemplate.setMessageMark(smsTemplate.getMessageMark());
            msgTemplate.setMessageType(smsTemplate.getMessageType());
            msgTemplate.setMessageAccount(smsTemplate.getMessageAccount());
            msgTemplate.setMessagePwd(smsTemplate.getMessagePwd());
            msgTemplate.setWay(smsTemplate.getWay());
            msgTemplate.setWayId(smsTemplate.getWayId());
            // 发送创蓝短信
            if (Objects.equals(msgTemplate.getWay(), MsgTemplateConsts.MSG_TEMP_WAY_CL)) {
                return SendSmsStrategyEnum.valueOf(SendSmsStrategyEnum.CL.desc).notifyMechanism.doSend(msgTemplate, sms);
            }
            // 发送阿里短信
            if (Objects.equals(msgTemplate.getWay(), MsgTemplateConsts.MSG_TEMP_WAY_Ali)) {
                return SendSmsStrategyEnum.valueOf(SendSmsStrategyEnum.ALI.desc).notifyMechanism.doSend(msgTemplate, sms);
            }
            // 发送掌上通短信
            if (Objects.equals(msgTemplate.getWay(), MsgTemplateConsts.MSG_TEMP_WAY_ZST)) {
                return SendSmsStrategyEnum.valueOf(SendSmsStrategyEnum.ZST.desc).notifyMechanism.doSend(msgTemplate, sms);
            }
        } catch (IllegalAccessException e) {
            log.error("[{}],发送异常，msg:{},errorCode:{}", "发送消息", e.getMessage(), PlatErrorCodeDict.ERROR_CODE_THIRD_SERVICE_ERROR, e);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_THIRD_SERVICE_ERROR);
        }
        return ZmnSmsConsts.MSG_SEND_ERROR;
    }

    private Integer sendWechatMsg(MsgTemplate msgTemplate, ZmnSms sms) throws IllegalAccessException {
        MsgWechatTemplate wechatTemplate = msgWechatTemplateService.findMsgWechatTemplateByTemplateIdAndWechatAppId(msgTemplate.getTemplateId(), sms.getWeChatAppId());
        if (Objects.isNull(wechatTemplate)) {
            log.error("[{}],发送异常，msg:{},data:{},errorCode:{}", "发送微信模板消息", "无配置数据", wechatTemplate, PlatErrorCodeDict.ERROR_CODE_PUSH_MSG_SEND_WECHAT_NO_TEMPLATE);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PUSH_MSG_SEND_WECHAT_NO_TEMPLATE);
        }
        msgTemplate.setWechatEndMessage(wechatTemplate.getWechatEndMessage());
        msgTemplate.setWechatMessage(wechatTemplate.getWechatMessage());
        msgTemplate.setWechatTempId(wechatTemplate.getWechatTempId());
        msgTemplate.setWechatId(wechatTemplate.getWechatId());
        return SendSmsStrategyEnum.valueOf(SendSmsStrategyEnum.WECHAT.desc).notifyMechanism.doSend(msgTemplate, sms);
    }

    /**
     * 描述：构建微信参数数据
     *
     * @param dio
     *            消息内容
     * @return java.lang.String
     * @author wangjie
     * @since 2020/6/19 14:04
     **/
    private String buildWeChatPram(SendSmsDIO dio) {

        WeChatSmsDIO weChatSms = dio.getWeChatSmsDIO();
        if (Objects.isNull(weChatSms)) {
            return "";
        }
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("{");
        if (Objects.nonNull(weChatSms.getFirst())) {
            stringBuilder.append("\"first\":{");
            weChartSmsDIOToJson(weChatSms.getFirst(), stringBuilder);
            stringBuilder.append("},");
        }
        if (Objects.nonNull(weChatSms.getFirst())) {
            for (int i = 0; i < weChatSms.getKeywordLinkedList().size(); i++) {
                stringBuilder.append("\"keyword").append(i + 1).append("\":{");
                weChartSmsDIOToJson(weChatSms.getKeywordLinkedList().get(i), stringBuilder);
                stringBuilder.append("},");
            }
        }
        if (Objects.nonNull(weChatSms.getRemark())) {
            stringBuilder.append("\"remark\":{");
            weChartSmsDIOToJson(weChatSms.getRemark(), stringBuilder);
            stringBuilder.append("}");
        } else {
            stringBuilder.deleteCharAt(stringBuilder.length() - 1);
        }
        stringBuilder.append("}");
        return stringBuilder.toString();
    }

    private StringBuilder weChartSmsDIOToJson(WeChatSmsValueDIO weChartSmsValueDIO, StringBuilder stringBuilder) {
        if (Objects.nonNull(weChartSmsValueDIO.getValue())) {
            stringBuilder.append("\"value\":\"").append(weChartSmsValueDIO.getValue()).append("\"");
        }
        if (Objects.nonNull(weChartSmsValueDIO.getColor())) {
            stringBuilder.append(",").append("\"color\":\"").append(weChartSmsValueDIO.getColor()).append("\"");
        } else {
            stringBuilder.append(",").append("\"color\":\"").append("#173177").append("\"");
        }
        return stringBuilder;
    }

    /**
     * 描述: 格式化百度模板消息参数
     *
     * @param linkedList
     *            百度模板消息参数
     * @return java.lang.String
     * @author wangjie date 2020/7/9 16:53
     **/
    private String baiduSmsDIOToJson(LinkedList<String> linkedList) {

        StringBuilder sb = new StringBuilder();
        sb.append("{");
        int size = linkedList.size() - 1;
        for (int i = 0; i < linkedList.size(); i++) {
            sb.append("\"keyword").append(i + 1).append("\":{");
            sb.append("\"value\":\"").append(linkedList.get(i)).append("\"");
            if (i == size) {
                sb.append("}");
            } else {
                sb.append("},");
            }
        }
        sb.append("}");
        return sb.toString();
    }

    private boolean checkBaiduFormIdNum(String formId) {

        ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();

        REDIS_KEY += formId;

        String sceneId = opsForValue.get(REDIS_KEY);

        if (StringUtil.isNotBlank(sceneId)) {
            return false;
        } else {
            opsForValue.set(REDIS_KEY, formId, REDIS_OUT_TIME, TimeUnit.DAYS);
            return true;
        }
    }
}
